package com.fll.fangyiuser.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fll.fangyicommon.entity.user.Message;
import com.fll.fangyicommon.utils.TimeUtil;
import com.fll.fangyiuser.config.SpringContextUtils;
import com.fll.fangyiuser.service.impl.MessageServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import java.io.IOException;

/**
 * @ServerEndpoint注解 是一个类层次的注解，它的功能主要是将目前的类定义成一个websocket服务器端,
 *                    注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 *                    userId：和哪位好友通信
 *                    roomId：房间号，防止串线
 */
@RestController
@ServerEndpoint(value = "/webSocketChat/{senderId}/{roomId}")
                                       //senderId: 发送方的用户id
@Slf4j
public class WebSocketChatController {

    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount;
    //实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key为用户标识
    private static final Map<Integer, WebSocketChatController> connections = new ConcurrentHashMap<>();
    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    private Integer senderId;
    private String roomId;

    private MessageServiceImpl businessMessageService = SpringContextUtils.getBean(MessageServiceImpl.class);

    /**
     * 连接建立成功调用的方法
     * 可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     * @param senderId：发送方id，即当前用户id
     * @param roomId：房间号
     * @param session：连接会话
     */
    @OnOpen
    public void onOpen(@PathParam("senderId") Integer senderId, @PathParam("roomId") String roomId, Session session) {

        this.session = session;
        this.senderId = senderId;           //用户user_id
        this.roomId = roomId;           //会话标识,整数,房间id：user_id + friend_id
        connections.put(senderId,this);   //添加到map中
        addOnlineCount();               //在线数加
        log.info("userId:" + senderId + "---" + "roomId:" + roomId);
        log.info("有新连接加入！发送用户：==={},当前在线人数为==={}",senderId,getOnlineCount());
//        System.out.println("有新连接加入！发送用户："+senderId+",当前在线人数为" + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        connections.remove(senderId);     //从map中移除
        subOnlineCount();                 //在线数减
        log.info("有一连接关闭,当前在线人数为：==={}",getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法，客户端发送过来的消息
     * @param message
     * @param session
     * 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        log.info("来自客户端的消息：==={}",message);
        JSONObject json = JSON.parseObject(message);
        Integer senderId = json.getInteger("senderId");               //发送人id
        Integer acceptorId = json.getInteger("acceptorId");         //接收人id
        String msg = json.getString("messageContent");              //需要发送的信息
        send(msg, senderId, acceptorId, roomId);
    }

    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("websocket连接发送错误！");
        error.printStackTrace();
    }

    /**
     * @param senderId 发送人
     * @param acceptorId 接收人
     * @param msg 消息内容
     * @param roomId 房间ID
     */
    public void send(String msg, Integer senderId, Integer acceptorId, String roomId){
        Message message = new Message();
        message.setSenderId(senderId);
        message.setAcceptorId(acceptorId);
        message.setMessageContent(msg);
        message.setSendTime(TimeUtil.getString(new Date()));
        message.setIsLast(0);
        message.setIsRead(0);
        try {
            Integer res = businessMessageService.insert(message);
            if (res != null) {
                //通知发送方
                WebSocketChatController sender = connections.get(senderId);
                //此处应该做房间号判断的，在同一个房间才发送
                sender.session.getBasicRemote().sendText(JSON.toJSONString(message));

                //通知接收方
                WebSocketChatController acceptor = connections.get(acceptorId);
                //此处应该做房间号判断的，在同一个房间才发送
                acceptor.session.getBasicRemote().sendText(JSON.toJSONString(message));

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketChatController.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketChatController.onlineCount--;
    }

}
